#include "Engine.h"
#include <algorithm>

XCourse* XCourse::mInstance = 0;

// XProfile

bool	XProfile::IsDone()
{
	return mDone == mAllTopics->size();
}

// XToken

void XToken::Parse(TiXmlElement* tokenElement)
{
	if (tokenElement->Attribute("Text"))
	{
		text = tokenElement->Attribute("Text");
	}
	else
	{
		text = " ";
	}

	spaces = 0;
	tabs = 0;
	newLine = false;
	id = 0;
	correct = true;
	price = 1;

	tokenElement->QueryIntAttribute("Spaces", &spaces);
	tokenElement->QueryIntAttribute("Tab", &tabs);
	tokenElement->QueryIntAttribute("Price", &price);

	char* attr = (char*)(tokenElement->Attribute("NewLine"));
	if (attr)
	{
		newLine = std::string("true") == strlwr(attr);
	}


	TiXmlElement* nextElement = tokenElement->FirstChildElement("Token");
	while (nextElement)
	{
		XToken* nextToken = new XToken();
		nextToken->Parse(nextElement);
		elements.push_back(nextToken);

		nextElement = nextElement->NextSiblingElement("Token");
	}
}

// XTask
XTask::XTask()
{
	mCurrentElements = &elements;
}

XTask::~XTask()
{
}

std::string XTask::GetBeforeCode()
{
	return beforeCode;
}

std::string XTask::GetDescription()
{
	return description;
}

bool XTask::ChooseToken(int number)
{
	bool result = mCurrentElements->at(number)->correct;

	mCurrentElements = &(mCurrentElements->at(number)->elements);
	return result;
}

void XTask::Parse(TiXmlElement* taskElement)
{
	if (taskElement->Attribute("Description"))
	{
		description = taskElement->Attribute("Description");
	}
	else
	{
		description = "Task";
	}

	if (taskElement->Attribute("Code"))
	{
		beforeCode = taskElement->Attribute("Code");
		int pos;
		while ((pos = beforeCode.find("<br>")) != -1)
		{
			beforeCode.replace(pos,4,"\n");
		}
	}
	else
	{
		beforeCode = "";
	}

	mStepSize = 3;
	taskElement->QueryIntAttribute("StepSize", &mStepSize);

	TiXmlElement* tokenElement = taskElement->FirstChildElement("Token");
	while (tokenElement)
	{
		XToken* token = new XToken();
		token->Parse(tokenElement);
		elements.push_back(token);

		tokenElement = tokenElement->NextSiblingElement("Token");
	}

}

int XTask::GetStepSize()
{
	return mStepSize;
}

bool	XTask::IsCorrect()
{
	return isCorrect;
}

bool	XTask::IsFinished()
{
	return isFinished;
}

ElementList* XTask::GetCurrentTokens()
{
	return &mCurrentTokens;
}

void XTask::GenerateTokens()
{
	mCurrentTokens.clear();

	int correctCount = min(mStepSize, mCurrentElements->size());
	int wrongCount = mStepSize - correctCount;

	ElementList::iterator it = mCurrentElements->begin();
	for (int i = 0; i < correctCount; ++i)
	{
		mCurrentTokens.push_back(*it);
		++it;
	}

	it = XCourse::GetSingleton()->GetTokenBase()->begin();
	int m = XCourse::GetSingleton()->GetTokenBase()->size();

	for (int i = 0; i < wrongCount; ++i)
	{
		int k = rand() % (m - i - correctCount - 1);
		for (int j = 0; j < k - 1; ++j)
		{
			++it;
			if (it ==  XCourse::GetSingleton()->GetTokenBase()->end())
				it =  XCourse::GetSingleton()->GetTokenBase()->begin();
		}

		bool findRand;
		do 
		{
			findRand = true;
			++it;
			if (it == XCourse::GetSingleton()->GetTokenBase()->end())
				it = XCourse::GetSingleton()->GetTokenBase()->begin();
			for (ElementList::iterator j = mCurrentTokens.begin(); j != mCurrentTokens.end(); ++j)
				if ((*j)->text == (*it)->text)
					findRand = false;
		}
		while (!findRand);

		mCurrentTokens.push_back(*it);
	}
}

void	XTask::Start()
{
	mCurrentElements = &elements;
	isFinished = false;
	isCorrect = true;

	GenerateTokens();
}

bool	XTask::ChooseToken(XToken* token)
{
	isCorrect = token->correct;

	if (IsCorrect())
	{
		mCurrentElements = &token->elements;
		if (mCurrentElements->size() == 0)
		{
			isFinished = true;
		}
		else
		{
			XCourse::GetSingleton()->AddScore(token->price);
			GenerateTokens();
		}
	}
	else
	{
		isFinished = true;
	}

	return IsCorrect();
}

// XTopic

void XTopic::Parse(TiXmlElement* topicElement)
{
	if (topicElement->Attribute("Name"))
	{
		name = topicElement->Attribute("Name");
	}
	else
	{
		name = "Topic";
	}
	
	TiXmlElement* taskElement = topicElement->FirstChildElement("Task");
	while (taskElement)
	{
		XTask* task = new XTask();
		task->Parse(taskElement);
		tasks.push_back(task);

		taskElement = taskElement->NextSiblingElement("Task");
	}

	tasksToNext = tasks.size();
	topicElement->QueryIntAttribute("NextLevel", &tasksToNext);
}

// XCourse

void XCourse::Load(std::string fileName)
{
	TiXmlDocument* document = new TiXmlDocument();

	document->LoadFile(fileName.c_str()); 

	TiXmlElement* rootElement = document->RootElement();
	TiXmlElement* courseElement = rootElement->FirstChildElement("Course");
	TiXmlElement* tokensElement = rootElement->FirstChildElement("Tokens");

	TiXmlElement* topicElemnt = courseElement->FirstChildElement("Topic");
	while (topicElemnt)
	{
		XTopic* topic = new XTopic();
		topic->Parse(topicElemnt);
		topics.push_back(topic);

		topicElemnt = topicElemnt->NextSiblingElement("Topic");
	}

	TiXmlElement* tokenElement = tokensElement->FirstChildElement("Token");
	while (tokenElement)
	{
		XToken* token = new XToken();
		token->Parse(tokenElement);
		token->correct = false;
		mTokenBase.push_back(token);

		tokenElement = tokenElement->NextSiblingElement("Token");
	}

	delete document;
}

void XCourse::GenerateTaskSet(int topic)
{
	mTopicIndex = topic;
	mTaskSet.clear();
	int n = topics.at(topic)->tasks.size();
	int k = topics.at(topic)->tasksToNext;
	k = k <= n ? k : n;

	int taskIndex = -1;
	for (int i = 0; i < k; ++i)
	{
		taskIndex += 1 + rand() % (n + i - k - taskIndex);
		mTaskSet.push_back(topics.at(topic)->tasks.at(taskIndex));
	}
}

ElementList*	XCourse::GetTokenBase()
{
	return &mTokenBase;
}

void	XCourse::StartNextTask()
{
	TaskList::iterator it = mTaskSet.begin();
	it = mTaskSet.erase(it);
	if (it == mTaskSet.end())
	{
		mProfile->FinishTopic(mTopicIndex);
		mTopicIndex = mTopicIndex + 1 >= topics.size() ? 0 : mTopicIndex + 1;
		GenerateTaskSet(mTopicIndex);
	}
}

void	XCourse::StartTopic(int topic)
{
	GenerateTaskSet(topic);
}

bool	XCourse::IsPriseOpened(int priseIndex)
{
	switch (priseIndex)
	{
	case PRISE_MORE_100:
		return GetScore() > 100;
	case PRISE_MORE_300:
		return GetScore() > 300;
	case PRISE_MORE_500:
		return GetScore() > 500;
	case PRISE_ONE_TOPIC:
		return mProfile->GetTopics()->size() > 1;
	case PRISE_HALF:
		return mProfile->GetTopics()->size() > topics.size() / 2 + 1;
	case PRISE_ALL:
		return mProfile->IsDone();
	}
	return false;
}

// XProfile

XProfile::XProfile()
{
	mScore = 0;
}
XProfile::~XProfile()
{
}
void XProfile::Create(TopicList* topicList)
{
	mDone = 0;
	mAllTopics = topicList;
	mTopicList.clear();
	mTopicList.push_back(mAllTopics->at(0));
	mScore = 0;
}
void XProfile::Save()
{
	FILE* file;
	fopen_s(&file, "../Data/Course/profile.txt","w");
	if ( file ) 
	{
		fprintf_s(file, "Topic count=%d\n", mTopicList.size());

		fclose(file);
	}
	// else - WTF??
}
int XProfile::GetScore()
{
	return mScore;
}
void XProfile::SetScore(int score)
{
	mScore = score;
}
void XProfile::Load(TopicList* topicList)
{
	mAllTopics = topicList;
	FILE* file;
	file = fopen("../Data/Course/Profile.txt", "r");
	if (!file)
	{
		Create(topicList);
		return;
	}

		
	mTopicList.clear();
	fscanf_s(file, "Topic count=%d\n", &mDone);

	for (int i = 0; i < mDone; ++i)
		mTopicList.push_back(mAllTopics->at(i));
	fclose(file);
}
void XProfile::FinishTopic(int topic)
{
	if (topic < mAllTopics->size())
	{
		mDone = min(mDone + 1, mAllTopics->size());
		if (mDone != mAllTopics->size())
		{
			mTopicList.push_back(mAllTopics->at(mDone));
		}
	}
}
TopicList* XProfile::GetTopics()
{
	return &mTopicList;
}